package vue.panneau3.panneau3Modele;
import java.awt.Color;

import javax.swing.JPanel;

import modele.Equation2D;
import vue.panneau3.Representation2D;
import vue.panneau3.Representation3D;
import vue.panneau3.panneau3Controleur.EtatPrecedantSuivantListener;
import vue.panneau3.panneau3Controleur.SelectionMatriceListener;
import vue.util.Point;

/**
 * <br>
 * Cette classe controleur permet<br>
 * de creer, et de manipuler une zone<br>
 * de trace de points et de<br>
 * fonctions dont les equations<br>
 * sont en ax1 + bx2 <= (i.e. >=) c<br>
 * <br>
 * <br>
 * dans le projet TER simplexe:<br>
 * c'est la zone du bas .<br>
 * <br>
 * pour creer une telle zone et la recuperer,<br>
 * il faut faire :<br>
 * <br>
 * Modele m = new Modele() ;<br>
 * <br>
 * Jpanel panneauBas = m.getJpanel() ;<br>
 * et mettre ce panneau dans un conteneur<br>
 * panneauPrincipal.add(panneauBas,BorderLayout.SOUTH) ;// par exemple<br>
 * <br>
 * <br>
 * <br>
 * ensuite on peut manipuler le panneau:<br>
 * en ajoutant/retirant des points:<br>
 * --------------------------------<br>
 * {@link #ajouterPoint(Point)}<br>
 * {@link #retirerPoint(float, float)}<br>
 * <code>
 * m.ajouterPoint(new Point(-18, -3, 2, "point de la matrice 2 coordonnees (-18)x1 + (-3)x2")) ;<br>
 * m.retirerPoint(-18, -3) ; // pour retirer le point de dessus<br>
 * </code>
 * <br>
 * <br>
 * en ajoutant/retirant des inequations:<br>
 * -------------------------------------<br>
 * {@link #ajouterEquation2D(Equation2D)}<br>
 * {@link #retirerEquation2D(float, float, boolean, float)}<br>
 * <code>
 * m.ajouterEquation2D(new Equation2D(1,1,Equation2D.SIGNE_INF_OU_EGAL,10,Color.BLUE)) ;<br>
 * m.retirerEquation2D(1, 1, Equation2D.SIGNE_INF_OU_EGAL, 10) ; // retire l inequation de dessus<br>
 * </code>
 * <br>
 * <br>
 * en specifiant la fonction a optimiser:<br>
 * --------------------------------------<br>
 * {@link #setFonctionAOptimiser(float, float)}<br>
 * <code>
 * m.setFonctionAOptimiser(2, 4) ; // fonction a optimiser 2x1 + 4x2 ici<br>
 * </code>
 * <br>
 * en nommant les axes X1 et X2:<br>
 * -----------------------------<br>
 * {@link #setLibelleX1(String)}<br>
 * {@link #setLibelleX2(String)}<br>
 * <code>
 * m.setLibelleX1("libelle de X1") ;<br>
 * m.setLibelleX2("libelle de X2") ;<br>
 * </code>
 * <br>
 * <br>
 * enfin on peut mettre un listener sur cette zone,<br>
 * ainsi on peut recuperer la matrice correspondant<br>
 * a un point (chaque point viens d'une matrice qui<br>
 * l' a engendre) si l utilisateur clique sur ce point:<br>
 * ----------------------------------------------------<br>
 * {@link #ajouterSelectionMatriceListener(SelectionMatriceListener)}<br>
 * <br>
 * <code>
 * m.ajouterSelectionMatriceListener(this) ;<br>
 *  // this doit alors implementer SelectionMatriceListener<br>
 *  // ----------------------------------------------------<br>
 *  // de ce fait doit posseder la methode <br>
 *  // public void selectionMatrice(int numeroMatrice)<br>
 *  // -----------------------------------------------<br>
 * public void selectionMatrice(int numeroMatrice) {<br>
 * 	System.out.println("on a clique sur le point dont la<"br>
 *    + "matrice a pour numero "+numeroMatrice);<br>
 * }<br>
 * </code>
 * <br>
 * <br>
 * on a ici un exemple complet<br>
 * d' une utilisation de cette classe:<br>
 * <br>
 * <br>
 * <br>
 * <br>
	 * <code>
	 * public class Test implements SelectionMatriceListener {<br>
	 *    Test () {<br>
	 *       Modele m = new Modele() ;<br>
	 *       <br>
	 *       /// ...<br>
	 *       /// ...<br>
	 *       <br>
	 *       // ici on cree une fenetre,<br>
	 *       // on y met le panneau avec:<br>
	 *       // JFrame fenetre = ...<br>
	 *       // ...<br>
	 *       // fenetre.getContentPane().add(m.getJpanel(),BorderLayout.CENTER) ;<br>
	 *       <br>
	 *       /// ...<br>
	 *       /// ...<br>
	 *       <br>
	 *       // le listener<br>
	 *       m.ajouterSelectionMatriceListener(this) ;<br>
	 * <br>
	 *       public void selectionMatrice(int numeroMatrice) {<br>
	 *         System.out.println(<br>
	 *           "on a choisis la matrice numero "<br>
	 *         + numeroMatrice);<br>
	 *       }<br>
	 *    }<br>
	 * }<br>
	 * </code>
	 * <br>
 * <br>
 * <br>
 * <br>
 * le panneau engendre peut afficher/rendre invisible:<br>
 *  - une grille (a 2 echelles :epais et fin) dont les echelles varient.<br>
 *  - des fonctions de zoom et de decalage.<br>
 *  - changer la taille des croix representant les points.<br>
 *  - afficher la fonction a optimiser.<br>
 *  - changer le nom d'un point.<br>
 * <br>
 * <br>
 * 
 * @author jean-marie codol
 *
 */
public class Modele {
	
	// la representation 2D.
	private Representation2D r2D ;
	
	// la representation 3D.
	private Representation3D r3D ;
	
	
	private boolean is3D = false ;
	
	/**
	 * constructeur.<br>
	 * se charge de cr�er les objets internes<br>
	 * invisibes de l'exterieur.<br>
	 * 
	 *
	 */
	public Modele(boolean is3D) {
		this.is3D = is3D ;
		if (is3D){
			r3D = new Representation3D();
			r3D.repaint() ;
		}else {
			r2D = new Representation2D(null,0,0,null);
			r2D.repaint() ;
		}
	}
	
	public JPanel getPanneau()
	{
		if (this.is3D)
			return r3D ;
		return r2D;
	}
	
	/**
	 * ajoute un point visible sur le panneau.<br>
	 * l'objet Point passe est un<br>
	 * com.um2.simplexe.client.panneau2D.Point<br>
	 * qu il faut instancier.<br>
	 * <br>
	 * on peut changer la couleur du point<br>
	 * au moment de sa creation:<br>
	 * <br>
	 * <code><br>
	 *          // comme ceci<br>
	 *  		Point p1 = new Point(-10,-10,1,"jojo") ;<br>
	 *          p1.setCouleur(Color.WHITE) ;<br>
	 *          <br>
	 *          ajouterPoint(p1) ;
	 * </code><br>
	 * 
	 * 
	 * 
	 * 
	 * @param p le point a ajouter
	 */
	public void ajouterPoint2D(Point p) {
		if (this.is3D)
		{
			try {
				throw new Exception("demande de placer un point 2D en mode 3D .") ;
			} catch (Exception e) {
				e.printStackTrace();
				return ;
			}
		}else {
			r2D.ajouterPoint(p) ;
			r2D.repaint() ;
		}
	}
	
	/**
	 * retire tout et ajoute un point unique visible sur le panneau.<br>
	 * l'objet Point passe est un<br>
	 * com.um2.simplexe.client.panneau2D.Point<br>
	 * qu il faut instancier.<br>
	 * <br>
	 * on peut changer la couleur du point<br>
	 * au moment de sa creation:<br>
	 * <br>
	 * <code><br>
	 *          // comme ceci<br>
	 *  		Point p1 = new Point(-10,-10,1,"jojo") ;<br>
	 *          p1.setCouleur(Color.WHITE) ;<br>
	 *          <br>
	 *          ajouterPoint(p1) ;
	 * </code><br>
	 * 
	 * 
	 * 
	 * 
	 * @param p le point a ajouter
	 */
	public void setPoint2DUnique(Point p) {
		if (this.is3D)
		{
			try {
				throw new Exception("demande de placer un point 2D en mode 3D .") ;
			} catch (Exception e) {
				e.printStackTrace();
				return ;
			}
		}else {
			r2D.retirerToutLesPoints() ;
			r2D.ajouterPoint(p) ;
			r2D.repaint() ;
		}
	}
	
	/**
	 * on ajoute une equation sous forme de droite.<br>
	 * elle aparaitra correctement.<br>
	 * <br>
	 * <br>
	 * @param e2D
	 */
	public void ajouterEquation2D(Equation2D e2D) {
		if (this.is3D)
		{
			try {
				throw new Exception("demande de placer une equation 2D en mode 3D .") ;
			} catch (Exception e) {
				e.printStackTrace();
				return ;
			}
		}
		r2D.ajouterEquation2D(e2D) ;
	}
	
	public void modifierEquation2D(Equation2D neweq,Equation2D equationCourante) 
	{
		if (this.is3D)
		{
			try {
				throw new Exception("demande de modifier une equation 2D en mode 3D .") ;
			} catch (Exception e) {
				e.printStackTrace();
				return ;
			}
		}
		r2D.modifierEquation2D(neweq,equationCourante);
	}	
	
	/**
	 * on retire une equation.<br>
	 * elle n apparaitra plus et sera supprime<br>
	 * de la memoire du composant.<br>
	 * <br>
	 * <br>
	 */
	public void retirerEquation2D(float X1 , float X2, String signe, float partieDroite) 
	{
		if (this.is3D)
		{
			try {
				throw new Exception("demande de retirer une equation 2D en mode 3D .") ;
			} catch (Exception e) {
				e.printStackTrace();
				return ;
			}
		}
		r2D.retirerEquation2D(X1,X2,signe,partieDroite) ;
	}
	
	public void supprimerEquation2D(Equation2D eq)
	{
		if (this.is3D)
		{
			try {
				throw new Exception("demande de supprimer une equation 2D en mode 3D .") ;
			} catch (Exception e) {
				e.printStackTrace();
				return ;
			}
		}
		r2D.supprimerEquation2D(eq);
	}
	
	/** 
	 * on retire un point<br>
	 * il n apparaitra plus et sera supprime<br>
	 * de la memoire du composant.<br>
	 * <br>
	 * @param X1
	 * @param X2
	 */
	public void retirerPoint2D(float X1 , float X2) {
		if (this.is3D)
		{
			try {
				throw new Exception("demande de retirer un point 2D en mode 3D .") ;
			} catch (Exception e) {
				e.printStackTrace();
				return ;
			}
		}
		r2D.retirerPoint(X1,X2) ;
		r2D.repaint() ;
	}
	
	
	
	
	/**
	 * on change la fonction a optimiser.<br>
	 * <br>
	 * le nouvelle fonction a optimiser aura pour equation:<br>
	 * en X1 le premier parametre<br>
	 * en X2 le deuxieme parametre<br>
	 * <br>
	 * <br>
	 * @param x1 le parametre X1 de la fonction a optimiser<br>
	 * @param x2 le parametre X2 de la fonction a optimiser<br>
	 */
	public void setFonctionAOptimiser2D(float x1,float x2) {
		if (this.is3D)
		{
			try {
				throw new Exception("demande de modifier la fonction a optimiser 2D en mode 3D .") ;
			} catch (Exception e) {
				e.printStackTrace();
				return ;
			}
		}
		r2D.setfonctionAOptimiserX1(x1) ;
		r2D.setfonctionAOptimiserX2(x2) ;
		r2D.repaint() ;
	}
	
	
	/**
	 * supprime tout.<br>
	 * on repart de zero.<br>
	 * <br>
	 * il n'est pas necessaire de refaire un<br>
	 * getJpanel pour re-recuperer un nouveau Jpanel.<br>
	 * <br>
	 * l'update se fait automatiquement.<br>
	 * <br>
	 *<br>
	 */
	public void reinitialiser() {
		if (this.is3D)
		{
			System.out.println("a faire : reinitialiser le panneau 3D !!!");
		} else {
			r2D.reinitialiser() ;
			r2D.repaint() ;
		}
	}
	
	
	/**
	 * c'est le panneau dans lequel le graphique 2D se passe.<br>
	 * <br>
	 * on peut le placer nimporte ou.<br>
	 * <br>
	 * <br>
	 * 
	 * @return
	 */
	public JPanel getJpanel() {
		if (this.is3D)
		{
			return r3D ;
		}
		return r2D ;
	}
	
	/**
	 * c'est le libelle de la variable X1.<br>
	 * <br>
	 *  
	 * @return
	 */
	public String getLibelleX1() {
		
		if (this.is3D)
		{
			System.err.println("a faire : get libelle x1 du panneau 3D !!!");
			return null ;
		}
		return r2D.getLibelleX1() ;
	}
	
	/**
	 * c'est le libelle de la variable X2.<br>
	 * <br>
	 *  
	 * @return
	 */
	public String getLibelleX2() {
		if (this.is3D)
		{
			System.err.println("a faire : get libelle x2 du panneau 3D !!!");
			return null ;
		}
		return r2D.getLibelleX2() ;
	}

	
	/**
	 * c'est le libelle de la variable X3.<br>
	 * dispo seulement en 3D<br>
	 *  
	 * @return
	 */
	public String getLibelleX3() {
		if (this.is3D)
		{
			System.err.println("a faire : get libelle x3 du panneau 3D !!!");
			return null;
		} else {
			try {
				throw new Exception(" ne peut pas rendre le libelle de x3 sur un panneau 2D !!!") ;
			} catch (Exception e) {
				e.printStackTrace();
				return null ;
			}
		}
	}

	
	/**
	 * 
	 * change le texte a cote de X1<br>
	 * par exemple on peut mettre gain en or<br>
	 * ou quantite de ble ou encore autre chose.<br>
	 * <br>
	 * 
	 * @param lebelle le texte a mettre en X1
	 */
	public void setLibelleX1(String libelle) {
		if (this.is3D)
		{
			System.err.println("a faire : set libelle x1 du panneau 3D !!!");
			return ;
		}
		r2D.setLibelleX1(libelle) ;
		r2D.repaint() ;
	}

	/**
	 * 
	 * change le texte a cote de X2<br>
	 * par exemple on peut mettre gain en or<br>
	 * ou quantite de ble ou encore autre chose.<br>
	 * <br>
	 * 
	 * @param lebelle le texte a mettre en X2
	 */
	public void setLibelleX2(String libelle) {
		if (this.is3D)
		{
			System.err.println("a faire : set libelle x2 du panneau 3D !!!");
			return ;
		}
		r2D.setLibelleX2(libelle) ;
		r2D.repaint() ;
	}
	
	/**
	 * 
	 * change le texte a cote de X2<br>
	 * par exemple on peut mettre gain en or<br>
	 * ou quantite de ble ou encore autre chose.<br>
	 * <br>
	 * 
	 * @param lebelle le texte a mettre en X2
	 */
	public void setLibelleX3(String libelle) {
		if (this.is3D)
		{
			System.err.println("a faire : set libelle x3 du panneau 3D !!!");
			return ;
		} else {
			try {
				throw new Exception(" ne peut pas changer le libelle de x3 sur un panneau 2D !!!") ;
			} catch (Exception e) {
				e.printStackTrace();
				return ;
			}
		}
	}
	
	/**
	 * on peut ecouter ce composant,<br>
	 * lorsqu on veut ecouter sur quel<br>
	 * matrice l utilisateur a appuye (quel point).<br>
	 * on utilise cette methode.<br>
	 * <br>
	 * on cree alors un SelectionMatriceListener.<br>
	 * et il devrai indiquer que faire lors d une selection.<br>
	 * <br>
	 * un exemple:<br>
	 * <br>
	 * <code>
	 * public class Test implements SelectionMatriceListener {<br>
	 *    Test () {<br>
	 *       Modele m = new Modele() ;<br>
	 *       <br>
	 *       /// ...<br>
	 *       /// ...<br>
	 *       <br>
	 *       // ici on cree une fenetre,<br>
	 *       // on y met le panneau avec:<br>
	 *       // JFrame Fenetre = ...<br>
	 *       // ...<br>
	 *       // Fenetre.getPanneauSud.add(m.getJpanel()) ;<br>
	 *       <br>
	 *       /// ...<br>
	 *       /// ...<br>
	 *       <br>
	 *       m.ajouterSelectionMatriceListener(this) ;<br>
	 * <br>
	 *       public void selectionMatrice(int numeroMatrice) {<br>
	 *         System.out.println(<br>
	 *           "on a choisis la matrice numero "<br>
	 *         + numeroMatrice);<br>
	 *       }<br>
	 *    }<br>
	 * }<br>
	 * </code>
	 * <br>
	 * @param listener une classe qui doit implementer 'public void selectionMatrice(int numeroMatrice)'
	 */
	public void ajouterSelectionMatriceListener(SelectionMatriceListener listener) {
		if (this.is3D) {
			try {
				throw new Exception(" ne peut pas mettre de listener sur un panneau 3D !!!") ;
			} catch (Exception e) {
				e.printStackTrace();
				return ;
			}
		}
		r2D.ajouterSelectionMatriceListener(listener) ;
	}
	
	
	
	/**
	 * change la couleur du point dont les coordonnees correspondent:<br>
	 * <br>
	 * @param x1 coordonnee x1 du point dont on change la couleur
	 * @param x2 coordonnee x2 du point dont on change la couleur
	 * @param c la couleur qu on veut mettre
	 */
	public void changerCouleurPoint2D(int x1,int x2,Color c) {
		if (this.is3D) {
			try {
				throw new Exception(" ne peut pas faire une operation sur un point 2D sur un panneau 3D !!!") ;
			} catch (Exception e) {
				e.printStackTrace();
				return ;
			}
		}
		r2D.changerCouleurPoint(x1,x2,c) ;
		r2D.repaint() ;
	}
	
	/**
	 * change la couleur de la droite representant l equation<br>
	 * dont les parametre sont passes:<br>
	 * 
	 * @param X1
	 * @param X2
	 * @param signe
	 * @param partieDroite
	 * @param c
	 */
	public void changerCouleurEquation2D(float X1 , float X2, String signe, float partieDroite, Color c) {
		if (this.is3D) {
			try {
				throw new Exception(" ne peut pas faire une operation sur une equation 2D sur un panneau 3D !!!") ;
			} catch (Exception e) {
				e.printStackTrace();
				return ;
			}
		}
		r2D.changerCouleurEquation2D(X1 , X2, signe, partieDroite, c) ;
		r2D.repaint() ;
	}

	
	
	
	public void addEtatPrecedantSuivantListener(EtatPrecedantSuivantListener listener) {
		if (this.is3D) {
			try {
				throw new Exception(" ne peut pas mettre de listener sur un panneau 3D !!!") ;
			} catch (Exception e) {
				e.printStackTrace();
				return ;
			}
		}
		r2D.addEtatPrecedantSuivantListener(listener) ;
	}
	
	
	
	
}
